#!/usr/bin/env python
# Copyright(c) 2010 Nuttachat Wisittipanit. All rights reserved.

from mahbo.lib import (GUTIBD,)
from mahbo.information.dataprocess.report.svmreport import SVMReport
from mahbo.information.database.utility.dbinterface import DatabaseInterface
from mahbo.utility.utility import (DataPrePackage,RESULTS,)

from minings import (Datap,SVMpm,)
from minings.classification.svm.main import ProcessSVM
from minings.factory.datafactory import DataFactory
from minings.utility.utility import (DatasetTools,RUN,)

import os,xlrd,xlwt,MySQLdb,cPickle,orange,numpy,string
from copy import deepcopy

Abr = GUTIBD.Abr.main


class SITE(object):
    
    def __init__(self,**kwargs):
        self.Site           = None
        self.Class_X        = None
        self.Class_1        = None
        self.Class_2        = None
        self.Class_3        = None
        self.__dict__.update(kwargs)
        
        
class IBSINFO(object):
    
    def __init__(self,**kwargs):
        #.sample_name -> 'Dys94_19_PCR1_16'
        self.sample_name    = None
        #.diagnosis -> 'IBS-A'
        self.diagnosis      = None
        self.__dict__.update(kwargs)
        

class ALLINFO(object):
    
    def __init__(self,**kwargs):
        #.sample_name -> 'Dys94_19_PCR1_16'
        self.sample_name    = None
        #.diagnosis -> 'IBS-A'
        self.diagnosis      = None
        self.__dict__.update(kwargs)


class GUTIBS(DatabaseInterface):
    
    def __init__(self,**kwargs):
        self.maindbname                 = 'gutibs'
        #table that keeps all the data for this project
        self.maintable                  = 'gutibs'
        self.maintablem                 = 'gutibsm'
        self.pthreshold                 = 0.1
        self.flow                       = None #FLOW instance
        self.maindataoption             = Datap.Option.fix
        self.mainpermremovelist         = ['Polyp','Diverticulitis','Normal Pouch','Pouchitis','Alcoholic','ALD','Non ALD','None']
        self.keeplist                   = ['IBS','Crohn','Ulcerative Colitis','Healthy Control']
        self.mainfixedcls               = 'IBS'
        self.mainrun                    = RUN()
        self.__dict__.update(kwargs)
        #Connect to MySQL orange-style also
        DatabaseInterface.__init__(self,self.maindbname,True)
        self.rawdata                    = {}
        self.getXcelProperty()
    
    def getXcelProperty(self):
        self.data_folder                = GUTIBD.Folder.Gutlhpcr.ibsraw
        self.output_folder              = GUTIBD.Folder.Gutlhpcr.ibsout
        self.svmoutput_file             = os.path.join(self.output_folder,'svm_gutibs.xls')
        #XCel Read properties
        self.ibs_abd_sfile              = 'LHPCR_Abundance_IBS.xls'
        self.ibs_abd_file               = os.path.join(self.data_folder,self.ibs_abd_sfile)
        #open sheet file
        self.ibs_abd_book               = xlrd.open_workbook(self.ibs_abd_file)
        #.ibs_abd_sheet = 'LHPCR_abd'
        self.ibs_abd_sheet              = self.ibs_abd_book.sheet_by_index(0)
        #.ibs_meta_sheet = 'LHPCR_IBS_meta'
        self.ibs_meta_sheet             = self.ibs_abd_book.sheet_by_index(1)
        #.ibs_ss_sheet = 'Sample Sites'
        self.ibs_ss_sheet               = self.ibs_abd_book.sheet_by_index(2)
        
        self.ibs_outfile                = os.path.join(self.output_folder,'GUTIBS_Information.xls') 
        self.ibs_bookwrite              = xlwt.Workbook() 
        self.col_width                  = 5000
        
    def doMain(self):
        isDataExist         = True
        #Check table exist or not
        self.mainTables     = ('gutibs',)
        for i in self.mainTables:
            try:
                self.maindata = self.t.query("""select * from %s""" % i)
            except (MySQLdb.ProgrammingError,):
                #Table i does not exist
                isDataExist = False
                break
        if not isDataExist:
            self.maindata = self.constructMainTables()
            self.t.write(self.maindbname,self.maindata,overwrite = True)
            self.modifyTable()
        self.getRawdataMySQL()
    
    def getInformation(self):
        self.IBSINFO_OBJ    = {} #{sample name:IBSINFO object, ..}
        self.ALLINFO_OBJ    = {} #{sample name:ALLINFO object, ..}
        self.SITE_OBJ       = {} #{sample site:SITE object, ..}
        self.class2index    = {} #{'IBS-A':0,'IBS-C':1,'IBS-d':2}
        self.classList      = [] #['IBS-A','IBS-C','IBS-d']
        cntClass            = 0
        #Get information from IBS meta sheet
        for row in range(self.ibs_meta_sheet.nrows):
            if row == 0:
                continue
            #value -> ['DYS','IBD2_082108','Dys94_19','Dys94_19_PCR1_16']
            value       = []
            for col in range(self.ibs_meta_sheet.ncols):
                value.append(str(self.ibs_meta_sheet.cell(row,col).value))
            sample_name = value[3]
            diagnosis   = value[4]
            self.IBSINFO_OBJ[sample_name] = IBSINFO(sample_name   = sample_name   ,
                                                    diagnosis     = diagnosis     ,
                                                    )
            try:
                self.class2index[diagnosis]
            except (KeyError,):
                self.class2index[diagnosis]     = cntClass
                self.classList.append(diagnosis)                
                cntClass                        += 1
        for row in range(self.ibs_abd_sheet.nrows):
            if row == 0: 
                continue
            value   = []
            for col in range(self.ibs_abd_sheet.ncols):
                value.append(str(self.ibs_abd_sheet.cell(row,col).value))
            sample_name = value[1]
            diagnosis   = value[4]
            self.ALLINFO_OBJ[sample_name] = ALLINFO(sample_name   = sample_name   ,
                                                    diagnosis     = diagnosis     ,
                                                    )
            try:
                self.class2index[diagnosis]
            except (KeyError,):
                self.class2index[diagnosis]     = cntClass
                self.classList.append(diagnosis)                
                cntClass                        += 1
        for row in range(self.ibs_ss_sheet.nrows):
            if row == 0: 
                continue
            value   = []
            for col in range(self.ibs_ss_sheet.ncols):
                value.append(str(self.ibs_ss_sheet.cell(row,col).value))
            try:
                site = str(int(float(value[0])))
            except (ValueError,):
                continue
            for j in range(len(value)):
                try:
                    self.SITE_OBJ[site]
                except KeyError:
                    self.SITE_OBJ[site] = SITE(Site = site)
                if   j == 2:
                    self.SITE_OBJ[site].Class_X    = value[j]
                elif j == 3:
                    self.SITE_OBJ[site].Class_1    = value[j]
                elif j == 4:
                    self.SITE_OBJ[site].Class_2    = value[j]
                elif j == 5:
                    self.SITE_OBJ[site].Class_3    = value[j]
    
    def constructMainTables(self):
        self.clearMainTables()
        #Get info from meta sheet
        self.getInformation()
        self.meta_sample_name       = []
        self.meta_class_X           = []
        self.meta_class_1           = []
        self.meta_class_2           = []
        self.meta_class_3           = []
        #.features -> ['260_40','265_73','269_10',..]
        self.features               = []
        self.sample                 = [] #The entire dataset
        a = []
        #Get info from abundance sheet
        for row in range(self.ibs_abd_sheet.nrows):
            value   = []
            for col in range(self.ibs_abd_sheet.ncols):
                value.append(str(self.ibs_abd_sheet.cell(row,col).value))
            #Need to block something here            
            if row != 0: #By Pass Class None
                #Get sample name
                sname   = value[1]
                #ssite -> '1','2'
                ssite   = int(float(value[2]))
                #label -> 'Healthy Control'
                label   = value[4]
                #if chksite = True, need to check site
                chksite = True
                #If I find sname matching keys in .IBSINFO_OBJ hash, it means I need to use diagnosis from IBSINFO ins
                if sname in self.IBSINFO_OBJ.keys():
                    a.append(sname)
                    label   = self.IBSINFO_OBJ[sname].diagnosis
                    chksite = False
                else:
                    #If sname not in .IBSINFO_OBJ keys and label is None, discard the entire row 
                    if label == 'None':
                        continue
                if chksite == True: 
                    #Only get ssite which is in ('19','20','21','22','23','24',) -> Sigmoid site
                    if ssite not in (19,20,21,22,23,24,):
                        continue                      
            local   = []
            for j in range(len(value)):
                #j -> column number
                if row == 0:
                    if j >= 5:
                        #value[j] -> '260.4','265.73333'
                        #otu -> '260.40','265.73'
                        otu = '%.2f' % float(value[j])
                        #u1 -> '260_40','265_73'
                        u1  = otu.replace('.','_')
                        ft  = orange.FloatVariable(u1)
                        self.features.append(ft)
                else:
                    if   j == 1:
                        sample_name_value   = value[j]
                        self.meta_sample_name.append(sample_name_value)
                    elif j == 2:
                        site_value          = str(int(float(value[j])))
                        try:
                            self.SITE_OBJ[site_value]
                            self.meta_class_X.append(self.SITE_OBJ[site_value].Class_X)
                            self.meta_class_1.append(self.SITE_OBJ[site_value].Class_1)
                            self.meta_class_2.append(self.SITE_OBJ[site_value].Class_2)
                            self.meta_class_3.append(self.SITE_OBJ[site_value].Class_3)
                        except (KeyError,):
                            self.meta_class_X.append('')
                            self.meta_class_1.append('')
                            self.meta_class_2.append('')
                            self.meta_class_3.append('')
                    if j >= 5:
                        local.append(float(value[j]))
                    if j == len(value) - 1:
                        local.append(self.class2index[label])
            if local != []:
                self.sample.append(deepcopy(local))
        #Construct orange class
        newClassVar         = orange.EnumVariable('Disease',values = self.classList)
        self.sample_d       = deepcopy(numpy.array(self.sample,'d'))
        finalDomain         = orange.Domain(self.features,newClassVar)
        data                = orange.ExampleTable(finalDomain,self.sample_d)
        sample_name_id      = orange.newmetaid()
        class_X_id          = orange.newmetaid()
        class_1_id          = orange.newmetaid()
        class_2_id          = orange.newmetaid()
        class_3_id          = orange.newmetaid()
        data.domain.addmeta(sample_name_id,orange.StringVariable('Sample_Name'))
        data.domain.addmeta(class_X_id,orange.StringVariable('Class_X'))
        data.domain.addmeta(class_1_id,orange.StringVariable('Class_1'))
        data.domain.addmeta(class_2_id,orange.StringVariable('Class_2'))
        data.domain.addmeta(class_3_id,orange.StringVariable('Class_3'))
        for i in range(len(data)):
            data[i]['Sample_Name']      = self.meta_sample_name[i]
            data[i]['Class_X']          = self.meta_class_X[i]
            data[i]['Class_1']          = self.meta_class_1[i]
            data[i]['Class_2']          = self.meta_class_2[i]
            data[i]['Class_3']          = self.meta_class_3[i]
        data = DatasetTools.finalBrush(data)
        return data
    
    def modifyTable(self):
        #Delete unwanted classes and modify c$Disease column
        unWantClass = ('Polyp','Diverticulitis','Alcoholic','ALD','Non ALD',)
        for i in unWantClass: 
            #i -> 'Polyp'
            self.RD.query("""delete from %s where %s="%s"
                          """ % (self.maintable     ,
                                 'c$Disease'        ,
                                 i                  ,
                                 ))
        d_list      = ['IBS-A','IBS-C','IBS-D','Crohn','Healthy Control','Ulcerative Colitis',]
        a           = string.join(d_list,"','")
        classList   = "('%s')" % a
        self.RD.query("""alter table %s modify %s ENUM%s
                      """ % (self.maintable,'c$Disease',classList,
                             ))
        #Create table 'gutibsm' aggregating 'IBS-A','IBS-C','IBS-D' to only 'IBS'
        #First create a duplicate table
        self.RD.query("""create table %s like %s
                      """ % (self.maintablem    ,
                             self.maintable     ,
                             ))
        self.RD.query("""insert %s select * from %s
                      """ % (self.maintablem    ,
                             self.maintable     ,
                             ))
        #Must alter the column to be TEXT first before I can modify to be ENUM
        self.RD.query("""alter table %s modify %s TEXT
                      """ % (self.maintablem,'c$Disease') )
        #Change 'IBS-A','IBS-C','IBS-D' to only 'IBS'
        self.RD.query("""update %s set %s="%s" where %s in ("%s","%s","%s")
                      """ % (self.maintablem,'c$Disease','IBS','c$Disease',
                             'IBS-A','IBS-C','IBS-D',))
        #Alter c$Disease to ENUM last
        d_list_new      = ['IBS','Crohn','Healthy Control','Ulcerative Colitis',]
        a_new           = string.join(d_list_new,"','")
        classList_new   = "('%s')" % a_new
        self.RD.query("""alter table %s modify %s ENUM%s
                      """ % (self.maintablem,'c$Disease',classList_new,
                             ))
                        
    def clearMainTables(self):
        for i in self.mainTables:
            try:
                self.RD.query("""drop table %s
                              """ % i)
            except (MySQLdb.OperationalError,):
                pass
    
    def getRawdataMySQL(self):
        self.doAll_bool = False
        tempraw         = []
        self.RD.query("""SELECT * FROM %s
                      """ % (self.RD.tab_info.tablename,))
        row             = self.RD.cursor.fetchall() 
        if row not in (None,()):
            #Check whether I have everything ready to construct a datapackage
            #One datapackage can spawn many data
            for i in row:
                #dataname -> 'gutmtpslhpcr_Entire'
                dataname    = i[self.RD.tab_info.name]
                #info -> INFO ins
                info        = cPickle.loads(i[self.RD.tab_info.info_obj])
                tempraw.append((dataname,info))
                try:
                    #find out if table dataname exists on main database or not
                    self.RD.query("""DESC %s
                                  """ % (dataname,))
                except (MySQLdb.ProgrammingError,):
                    #If atleast one dataname does not exist, trigger doAll
                    self.doAll_bool = True
                    break
        else:
            self.doAll_bool = True 
        if self.doAll_bool:
            self.doAll()
        else:
            for i in tempraw:
                #i -> (dataname,info,)
                tempdata            = self.t.query("""SELECT * FROM %s""" % i[0])
                tempdata            = DatasetTools.finalBrush(tempdata)
                self.rawdata[i[0]]  =  GUTIBSDataPackage(fullname       = i[0]                  ,
                                                         data           = tempdata              ,
                                                         dataoption     = i[1].dataoption       ,
                                                         permremovelist = i[1].permremovelist   ,
                                                         keeplist       = i[1].keeplist         ,
                                                         fixedcls       = i[1].fixedcls         ,
                                                         matrix         = i[1].matrix           ,
                                                         pair           = i[1].pair             ,
                                                         run            = i[1].run              ,
                                                         Class_X        = i[1].Class_X          ,
                                                         Class_1        = i[1].Class_1          ,
                                                         Length         = i[1].Length           ,
                                                         )
    
    def doAll(self):
        ##########################
        ###Start Gathering Data###
        ##########################
        #.keyRank -> ['gutibs_Entire','gutibs_Ileum',]
        self.keyRank                    = []
        self.getAlldata()
    
    def getAlldata(self):
        #Get 'Entire'
        xname                  = 'Entire'
        d_entire               = self.t.query("""SELECT * FROM %s  
                                              """ % (self.maintablem     ,
                                                     ))
        #fullname -> 'gutibsm_Entire'
        fullname               = '%s_%s' % (self.maintablem,xname)
        self.rawdata[fullname] = GUTIBSDataPackage(
                                 fullname           = fullname                  ,data       = d_entire              ,dataoption = self.maindataoption   ,
                                 permremovelist     = self.mainpermremovelist   ,keeplist   = self.keeplist         ,fixedcls   = self.mainfixedcls     ,        
                                 run                = self.mainrun              ,Length     = len(d_entire)         ,
                                 )                                 
        self.keyRank.append(fullname)
        #Record Data
        for i in self.keyRank:
            #i -> 'gutibsm_Entire'
            fullname                    = i
            self.rawdata[i].data        = DatasetTools.finalBrush(self.rawdata[i].data)
            try:
                self.t.write(fullname,self.rawdata[i].data,overwrite = True)
            except (MySQLdb.OperationalError,):
                pass
            info        = INFO(fullname         = self.rawdata[i].fullname          ,
                               dataoption       = self.rawdata[i].dataoption        ,
                               permremovelist   = self.rawdata[i].permremovelist    ,
                               keeplist         = self.rawdata[i].keeplist          ,
                               fixedcls         = self.rawdata[i].fixedcls          ,
                               matrix           = self.rawdata[i].matrix            ,
                               pair             = self.rawdata[i].pair              ,
                               Class_X          = self.rawdata[i].Class_X           ,
                               Class_1          = self.rawdata[i].Class_1           ,
                               Class_2          = self.rawdata[i].Class_2           , 
                               Class_3          = self.rawdata[i].Class_3           ,                            
                               Length           = self.rawdata[i].Length            ,
                               )
            info_string = MySQLdb.escape_string(cPickle.dumps(info,2))
            #Determine to insert new or update the table
            self.RD.query("""select %s from %s where %s="%s"
                          """ % ( self.RD.tab_info.name         ,
                                  self.RD.tab_info.tablename    ,
                                  self.RD.tab_info.name         ,
                                  fullname                      ,
                                  ))
            row         = self.RD.cursor.fetchone()
            if row not in (None,()):
                #if table fullname exist,update
                self.RD.query("""update %s set %s="%s" where %s="%s"
                              """ % ( self.RD.tab_info.tablename        ,
                                      self.RD.tab_info.info_obj         ,
                                      info_string                       ,
                                      self.RD.tab_info.name,fullname    ,
                                      ))
            else:
                self.RD.query("""insert into %s (%s,%s) values  ("%s","%s")
                              """ % ( self.RD.tab_info.tablename        ,
                                      self.RD.tab_info.name             ,
                                      self.RD.tab_info.info_obj         ,
                                      fullname                          ,
                                      info_string                       ,
                                      ))
                
    def ci(self):
        self.cur_col += 1
        #Increase and return current column
        return self.cur_col - 1
    
    def ri(self):
        self.cur_row += 1
        return self.cur_row - 1
    
    def processDataFactory(self):
        for i in self.rawdata:
            #i -> 'gutibs_Entire'
            #self.rawdata[i] -> GUTIBSDataPackage,DataPrePackage ins
            for j in self.rawdata[i].datapackages:
                #j -> DataPackage instance
                dname       = j.datasetname
                doDatafact  = True
                #Upload information for a dataset 'rdp10level1_Entire_Crohn_Healthy Control'
                self.RD.query("""select * from %s where %s="%s"
                              """ % (self.RD.tab_results.tablename      ,
                                     self.RD.tab_results.datasetname    ,
                                     dname                              ,
                                     ))
                row         = self.RD.cursor.fetchone()
                if row in (None,()):
                    #If dataset do not exist,mark as freshy    -> True
                    freshy      = True
                else:
                    freshy      = False
                    #result_obj -> RESULTS ins
                    result_obj  = cPickle.loads(row[self.RD.tab_results.result_obj])
                    datafact    = result_obj.datafact   
                    if datafact == None:
                        doDatafact     = True
                    else:
                        #self.flow -> FLOW ins
                        #DataFactory instance exists
                        if self.flow.REdatafact:
                            #if flow.REdatafact -> True,redo it
                            doDatafact = True
                        else:
                            doDatafact = False
                if doDatafact:
                    df = DataFactory(datapackage = j                 ,                                                                                                       
                                     run         = RUN()             ,
                                     )
                    df.getDataPipeline()
                else:
                    continue
                if freshy:
                    #in anycase,if freshy -> True,do anew anyway (only record DataFactory instance)
                    result_obj          = RESULTS()
                    result_obj.datafact = df
                    result_obj_string   = MySQLdb.escape_string(cPickle.dumps(result_obj,2))
                    self.RD.query("""insert into %s (%s,%s) values  ("%s","%s")
                                  """ % (self.RD.tab_results.tablename      ,    
                                         self.RD.tab_results.datasetname    ,
                                         self.RD.tab_results.result_obj     ,
                                         dname                              ,
                                         result_obj_string                  ,
                                         ))
                else:
                    #freshy -> False,doDatafact -> True,come in here
                    result_obj.datafact = df
                    result_obj_string   = MySQLdb.escape_string(cPickle.dumps(result_obj,2))
                    self.RD.query("""update %s set %s="%s" where %s="%s"
                                  """ % (self.RD.tab_results.tablename      ,
                                         self.RD.tab_results.result_obj     ,
                                         result_obj_string                  ,
                                         self.RD.tab_results.datasetname    ,
                                         dname                              ,
                                         ))
                    
    def gatherRecordInformation(self):
        #.dset -> {gutibsm_Entire__IBS__Ulcerative Colitis: RESULTS ins, ..}
        self.dset       = {}
        #.dsort -> [gutibsm_Entire__IBS__Ulcerative Colitis, ..]
        self.dsort      = []
        #.nameabr -> [gutibsm_Entire__IBS__Ulcerative Colitis, ..]
        self.nameabr    = [] #List of abbrevation names
        #Initial Running
        self.RD.query("""select * from %s
                      """ % self.RD.tab_results.tablename)
        row         = self.RD.cursor.fetchall()
        if row in (None,()):
            return
        #Gather information
        for i in row:
            #datasetname -> 'gut_Endo_Ileum__Crohn__Healthy Control'
            datasetname             = i[self.RD.tab_results.datasetname]             
            #result_obj  -> RESULTS instance
            result_obj              = cPickle.loads(i[self.RD.tab_results.result_obj])
            self.dset[datasetname]  = result_obj
            self.dsort.append(datasetname)            
        self.dsort.sort()
        for i in self.dsort:
            nameAbr                 = self.getAbrName(i)
            self.nameabr.append(nameAbr)
    
    def processSVM(self):
        #.dsort -> [gutibsm_Entire__IBS__Ulcerative Colitis, ..]
        for i in range(len(self.dsort)):
            #dname -> gutibsm_Entire__IBS__Ulcerative Colitis
            dname           = self.dsort[i]
            #result_obj -> RESULTS ins
            result_obj      = self.dset[dname]
            #datafact -> DataFactory ins
            datafact        = result_obj.datafact
            #results_svn -> RES ins
            results_svm     = result_obj.results_svm
            runSVM          = False
            if results_svm != None:
                #if reslts_svn exists,check flow.REsvm
                if self.flow.REsvm:
                    #if flow.REsvm is True,do it, one by one
                    runSVM  = True
                else:
                    continue
            else:
                runSVM      = True
            if runSVM:
                psvm = ProcessSVM(runLearner  = (SVMpm.Kern.RBF,)   ,
                                  drtn        = (
                                                 SVMpm.Drtn.NORM    ,
                                                 SVMpm.Drtn.B2UP    ,
                                                 )                  ,                            
                                  datafact    = datafact            ,
                                  )
                psvm.mainRun()
                #psvm.mainres -> RES instance
                result_obj.results_svm  = psvm.mainres
                result_obj_string       = MySQLdb.escape_string(cPickle.dumps(result_obj,2))
                self.RD.query("""update %s set %s="%s" where %s="%s"                                                                                    
                              """ % (self.RD.tab_results.tablename      ,
                                     self.RD.tab_results.result_obj     ,
                                     result_obj_string                  ,
                                     self.RD.tab_results.datasetname    ,
                                     dname                              ,
                                     ))
    
    def SVMXcelRecord(self):
        svmrp = SVMReport(output_file  = self.svmoutput_file    ,
                          dset         = self.dset              ,
                          dsort        = self.dsort             ,
                          nameabr      = self.nameabr           ,
                          )
        svmrp.xcelRecord()
        
    def getAbrName(self,dset):
        #datasetname -> 'gutibsm_Entire__Healthy Control__IBS'
        #return
        a               = dset.find('__')
        nameM           = dset[a+2:] #'Colon_Lumen__Crohn_Colon__Crohn_Lumen'
        return nameM
        

class GUTIBSDataPackage(DataPrePackage):
    
    def __init__(self,**kwargs):
        #Arbitrary properties
        self.Class_X        = None
        self.Class_1        = None
        self.Class_2        = None
        self.Class_3        = None
        self.__dict__.update(kwargs)
        DataPrePackage.__init__(self,**kwargs)


class INFO(object):
    
    def __init__(self,**kwargs):
        self.fullname       = ''
        self.dataoption     = Datap.Option.fix
        self.permremovelist = ['']
        self.keeplist       = []
        self.fixedcls       = ''
        self.matrix         = [ [], [] ]
        self.pair           = []
        self.run            = None
        #Arbitrary properties
        self.Class_X        = None
        self.Class_1        = None
        self.Class_2        = None
        self.Class_3        = None
        self.Length         = None
        self.__dict__.update(kwargs)
        
        